﻿using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Cache.Interfaces;
using Core.AbstractEntities;
using Stack.Entities;

namespace Cache.Entities
{
    /// <summary>
    /// Provider for XML cache
    /// </summary>
    public class XMLCacheProvider : ICacheProvider
    {
        /// <summary>
        /// Constructor to setting the valus by default
        /// </summary>
        public XMLCacheProvider()
        {
            Settings = new XmlWriterSettings();
            Settings.Indent = true;
            Settings.NewLineOnAttributes = true;
            Key = @"C:\hpPile.xml";
        }

        #region  Members
        private XmlWriterSettings Settings { get; set; }
        #endregion

        #region ICacheProvider Members
        /// <summary>
        /// Pile to manage
        /// </summary>
        public HpPile HpPile
        {
            get;
            set;
        }
        /// <summary>
        /// Save the pile's information in the cache
        /// </summary>
        public void Store()
        {
            XmlWriter writter = XmlWriter.Create(Key, Settings);
            writter.WriteStartDocument();
            writter.WriteStartElement("hpPile");
            writter.WriteAttributeString("date", DateTime.Now.ToString());
            //Store of the elements in the pile
            writter.WriteStartElement("hpElements");

            foreach (HpElement hpElement in this.HpPile)
            {

                writter.WriteStartElement("item");
                writter.WriteElementString("value", hpElement.Value.ToString());
                writter.WriteElementString("type", hpElement.Type.ToString());
                writter.WriteElementString("stored", hpElement.Stored.ToString());
                writter.WriteEndElement();
            }
            writter.WriteEndElement();

            //Store of the elements in the memory
            writter.WriteStartElement("hpElemenetInMemory");
            foreach (HpElement hpElement in this.HpPile.Memory)
            {

                writter.WriteStartElement("item");
                writter.WriteElementString("nomVar", hpElement.NomVar);
                writter.WriteElementString("value", hpElement.Value.ToString());
                writter.WriteElementString("type", hpElement.Type.ToString());
                writter.WriteEndElement();
            }
            writter.WriteEndElement();
            writter.WriteEndDocument();
            writter.Flush();
            writter.Close();
            //Set to true property "ContainsData"
            CointainsData = true;
        }
        /// <summary>
        /// Restore the cache's information to the pile 
        /// </summary>
        public HpPile Restore()
        {
            HpPile hpPile = new HpPile();

            hpPile = (HpPile)RestoreElement_Internal(hpPile, "hpElements");
            hpPile.Memory = (HpMemory)RestoreElement_Internal(hpPile.Memory , "hpElemenetInMemory");

            return hpPile;
        }
        /// <summary>
        /// Internal method for recovering elements in the XML document
        /// </summary>
        /// <param name="hpPile">HpPile / HpPile.Memory</param>
        /// <param name="elements">name of the "node"</param>
        private HpCollection RestoreElement_Internal(HpCollection hpPile, XName elements)
        {

            XElement root = XElement.Load(Key);
            var hpElements =
                from el in root.Elements(elements).Elements("item")
                select el;

            foreach (var el in hpElements)
            {
                hpPile.AddElement(new HpElement()
                {
                    Type = System.Type.GetType(el.Element("type").Value),
                    Value = Convert.ChangeType(el.Element("value").Value, System.Type.GetType(el.Element("type").Value)),
                    NomVar = (el.Element("nomVar") != null) ? el.Element("nomVar").Value : ""
                });
            }

            return hpPile;
        }
        /// <summary>
        /// Specify if the cache contains data
        /// </summary>
        public bool CointainsData
        {
            get;
            set;
        }
        /// <summary>
        /// Key to specify the "name" of the cache
        /// </summary>
        public string Key
        {
            get;
            set;
        }
        /// <summary>
        /// Force to delete the cache
        /// </summary>
        public void Flush()
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}
